/**
 * Created by JustinChow on 2016/11/17.
 */

"use strict";

const Damage = require("./DamageClass");
const Bullet = require("./BulletClass");

const ATTACK_TYPE_COMMON = 1;
const ATTACK_TYPE_SKILL  = 2;

const PROPS_TYPE_DAMAGE = 1;
const PROPS_TYPE_BULLET = 2;

const ATTACK_LEVEL_PERCENTAGE = 1;
const ATTACK_LEVEL_CONST = 2;

function Props(staticId, propsInfo) {
    if (!propsInfo) return;

    this.staticId = staticId;
    this.bullets  = [];

    this.staticConfig = this.loadConfig();

    this.attackType = this.staticConfig.attackType || -1;
    this.propType   = this.staticConfig.propType   || -1;
    this.bulletId   = this.staticConfig.bulletId   || [];
    this.cd         = this.staticConfig.cd         || 0;

    this.levelType  = this.staticConfig.levelType  || ATTACK_LEVEL_PERCENTAGE;
    this.levelValue = this.staticConfig["level_" + propsInfo.level] || 0;
}

Props.prototype.loadConfig = function () {
    return {};
};

function PropsHandler(gameServer, socket) {
    this.gameServer = gameServer;
    this.socket = socket;

    this.spellCaster = this.owner;

    this.propsInfo = {};

    Object.keys(this.propsInfo).forEach(propsId => {
        // Props Init, On Init Props Must Useble
        this.propsInfo[propsId].cdTime = new Date() - 86400 * 1e3;
    });

    this.propsList = [];
    this.damageList = [];
}

module.exports = PropsHandler;

PropsHandler.prototype.update = function () {
    var time = new Date();

    for (let pid = 0; pid < this.propsList.length; pid ++){
        let prop = this.propsList[pid];
        for (let bid = 0; bid < prop.bullets.length; bid ++) {
            let bullet = prop.bullets[bid];

            bullet.move();

            if (bullet.added && bullet.removed) {
                // Todo: If Bullet.removed Then Split From Array, Then this.gameServer.removeNode()
                prop.bullets.splice(bid, 1);
                this.gameServer.removeNode(bullet);
                this.onDamageSpawn(bullet.damageId, bullet.position);
            } else if (bullet.added && !bullet.removed && collide) {
                // Todo: Calc Collision With Other Objects, If Collide Call onDamageSpawn
                prop.bullets.splice(bid, 1);
                this.gameServer.removeNode(bullet);
                this.onDamageSpawn(bullet.damageId, bullet.position);
            } else {
                // Update Position
                this.gameServer.quadTree.update(bullet);
            }
        }

        // Todo: Loop this.propsList, Then Check this.bullets.length In Each Props, Empty Then Remove The Props From this.propsList
        if (prop.bullets.length <= 0) this.propsList.splice(pid, 1);
    }

    this.onDamageExpire();

    for (let did = 0; did < this.damageList.length; did++) {
        let damage = this.damageList[did];

        // Still Under Delay Time
        if (time - damage.time < damage.delay) continue;

        // Todo: Calc Damage For People
    }
};

PropsHandler.prototype.onPropsSpawn = function (propsId, position) {
    var bullets = [];

    // Check If I Can Use The Prop
    if (!this.propsInfo[propsId]) return bullets;

    var props = new Props(propsId, this.propsInfo[propsId]);

    // Check If Still Under Cd Mode
    if (new Date() - this.propsInfo[propsId].cdTime < props.cd) {
        return bullets;
    }

    // Prepare Spell
    this.propsInfo[propsId].cdTime = new Date();
    this.propsList.push(props);
    for (let bid = 0; bid < props.bulletId.length; bid++) {
        bullets.push(new Bullet(
            this.gameServer.getNewObjectId(),
            this,
            this.socket.playerTracker.player.position,
            this.gameServer,
            props.bulletId[bid],
            position
        ));
    }

    this.onBulletSpawn(bullets);
};

PropsHandler.prototype.onBulletSpawn = function (bullets) {
    // Cast Spell Todo Warn: This SetTimeOut Method Need To Set Each Bullet Delay Time
    for (let bid = 0; bid < bullets.length; bid ++){

        setTimeout(function (bullet) {

            // Todo: WARNING !!! Spell Cast From A (Player Position) To B, As The Player Move,
            // Todo: WARNING !!! The Position Changes From A To C, The Last Few Bullets Fly From C To B May Out Of Range
            bullet.setPosition(this.socket.playerTracker.player.position);
            this.gameServer.addNode(bullet);
            bullet.added = true;    // Mark That Bullet Added To Screen, Do Move Logic After This

        }.bind(this), bullets[bid].delay * bid, bullets[bid]);

    }
};

PropsHandler.prototype.onDamageSpawn = function (damageId, position) {
    if (!damageId) return;

    // Create Damage && Add Into damageList
    // Todo: After All Player Move Then Calc The Damage && Then Calc If Damage Expires
    let damage = new Damage(
        this.gameServer.getNewObjectId(),
        this.socket.playerTracker,
        position,
        this.gameServer,
        damageId
    );
    this.gameServer.damages.push(damage);
    this.damageList.push(damage);
};

PropsHandler.prototype.onDamageExpire = function () {
    for (let did = 0; did < this.damageList.length; did++) {
        if (new Date() - this.damageList[did].time >= this.damageList[did].holdTime) {
            this.gameServer.removeNode(this.damageList[did]);
            this.damageList.splice(did, 1);
        }
    }
};